﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Qing.Dll;
using Qing.Lang;

namespace Qing.Std {

    class Anti : Native {
        public override string Name { get; set; } = "取反";
        public override string Desc { get; set; } = "参数1-任意，返回逻辑；对参数1转为逻辑值后再取反";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return new Expr(TP.Bool, !args[0].ToBool());
            }

            return Expr.Err("取反函数参数不足");
        }

    }

    class Del : Native {
        public override string Name { get; set; } = "删除";
        public override string Desc { get; set; } = "参数1-字符串|对象，参数2-逻辑|字符串，返回任意；参数1为字符串时，从语境中删除对应的值，若此时参数2为真，限定从当前语境删除；当参数1为对象时，参数2必须为字符串，从对象中删除参数2对应的属性或方法";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args.Count == 1) {
                    return ctx.Remove(args[0].Str());
                } else {
                    if (args[1].Tp == TP.Bool && (bool)args[1].Val! == true) {
                        return ctx.RemoveNow(args[0].Str());
                    }else if (args[0].Tp == TP.Obj && args[1].Tp == TP.Str) {
                        return args[0].Obj().RemoveNow(args[1].Str());
                    }
                }
                
            }

            return Expr.Err("删除函数参数错误");
        }

    }

    class Copy : Native {
        public override string Name { get; set; } = "复制";
        public override string Desc { get; set; } = "参数1-任意，返回任意；复制参数1，注意是简单复制，对于集合类型，只是简单复制引用";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return args[0].Dup();
            }
            return Expr.Err("复制函数参数不足");
        }

    }

    class Clone : Native {
        public override string Name { get; set; } = "拷贝";
        public override string Desc { get; set; } = "参数1任意，返回任意；复制参数1，这里时深拷贝，对于集合类型，也会将内部的数据也会复制一份新的";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return args[0].Clone();
            }
            return Expr.Err("拷贝函数参数不足");
        }

    }

    class Eval : Native {
        public override string Name { get; set; } = "执行";
        public override string Desc { get; set; } = "参数1-字符串|大括号，返回任意；执行字符串或大括号中的代码";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count > 0) { 
                if (args[0].Tp == TP.Brace) {
                    return Expr.EvalExprs(args[0].List!, ctx);
                }else if (args[0].Tp == TP.Str) {
                    return Expr.EvalExprs(new Parser().Parse(args[0].Str(), ctx), ctx);
                }
                
            }
            return Expr.Err("执行函数参数不足");
        }

    }

    class TypeOf : Native {
        public override string Name { get; set; } = "取类型";
        public override string Desc { get; set; } = "参数1-任意，返回字符串；返回参数1对应类型的字符串";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                return new Expr(TP.Str, TPkit.typeName(args[0].Tp));
            }
            return Expr.Err("取类型函数参数不足");
        }

    }


    class Include : Native {
        public override string Name { get; set; } = "包含";
        public override string Desc { get; set; } = "参数-1字符串，可选参数2-逻辑，返回任意|对象；执行参数1对应文件中的代码，如果参数2为真，则会在一个对象语境中执行代码，并返回这个对象";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args[0].Tp == TP.Obj) {
                    var map = args[0].Ctx().Map;
                    foreach(var item in map) {
                        ctx.PutNow(item.Key, item.Value);
                    }
                    return new Expr(TP.Int, map.Count);
                }else if (args[0].Tp == TP.Str) {
                    string path = args[0].Str();
                    string script = path;

                    bool module = false;
                    if (args.Count > 1) {
                        module = args[1].ToBool();
                    }

                    if (path.StartsWith("http://") || path.StartsWith("https://")) {
                        HttpWebRequest request = WebRequest.CreateHttp(path);
                        request.Method = "GET";

                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                        using (Stream responseStream = response.GetResponseStream()) {
                            using (StreamReader sReader = new StreamReader(responseStream)) {
                                script = sReader.ReadToEnd();
                            }
                        }

                        if (module) {
                            Obj moduleCtx = new Obj(Env.LibCtx);
                            Expr.EvalExprs(new Parser().Parse(script, moduleCtx, path), moduleCtx);
                            return new Expr(TP.Obj, moduleCtx);

                        } else {
                            return Expr.EvalExprs(new Parser().Parse(script, ctx), ctx);
                        }


                    } else {
                        if (!path.StartsWith("/") && !path.Contains(":")) {
                            path = Directory.GetCurrentDirectory() + '/' + path;
                        }
                        if (!File.Exists(path)) {
                            return Expr.Err("包含函数的文件参数对应的文件不存在");
                        }

                        script = File.ReadAllText(path);


                        string originDir = Directory.GetCurrentDirectory();

                        FileInfo fi = new FileInfo(path);
                        string dir = fi.DirectoryName!;
                        Directory.SetCurrentDirectory(dir);


                        if (module) {
                            Obj moduleCtx = new Obj(Env.LibCtx);
                            Expr.EvalExprs(new Parser().Parse(script, moduleCtx, path), moduleCtx);
                            Directory.SetCurrentDirectory(originDir);
                            return new Expr(TP.Obj, moduleCtx);

                        } else {
                            Expr res = Expr.EvalExprs(new Parser().Parse(script, ctx), ctx);
                            Directory.SetCurrentDirectory(originDir);
                            return res;
                        }


                    }

                    
                    
 
                }

            }
            return Expr.Err("包含函数参数不足");
        }
    }



    class Import : Native {
        public override string Name { get; set; } = "引入";
        public override string Desc { get; set; } = "参数1-字符串，返回模块；将参数1对应的代码文件作为模块引入到当前代码中，模块在第一次取值时会转换为对象，模块是全局唯一的";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count > 0) {
                if (args[0].Tp == TP.Str) {
                    string path = args[0].Str();
                    string fullPath = path;
                    string script = "";
                    if (path.StartsWith("http://") || path.StartsWith("https://")) {
                        HttpWebRequest request = WebRequest.CreateHttp(path);
                        request.Method = "GET";

                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                        using (Stream responseStream = response.GetResponseStream()) {
                            using (StreamReader sReader = new StreamReader(responseStream)) {
                                script = sReader.ReadToEnd();
                            }
                        }

                    } else {
                        if (!path.StartsWith("/") && !path.Contains(":")) {
                            path = Directory.GetCurrentDirectory() + '/' + path;
                        }
                        if (!File.Exists(path)) {
                            return Expr.Err("引入函数的文件参数对应的文件不存在");
                        }

                        fullPath = Path.GetFullPath(path);
                        script = File.ReadAllText(path);
                    }

                    
                    if (Env.ModuleMap.ContainsKey(fullPath)) {
                        return Env.ModuleMap[fullPath];
                    } else {
                         
                        /*Ctx moduleCtx = new Ctx(Env.libCtx);
                        Expr.evalExprs(Parser.makeExprs(script, moduleCtx), moduleCtx);
                        Expr module = new Expr(TP.obj, moduleCtx);
                        Env.moduleMap[fullPath] = module;
                        return module;*/
                        Expr module = new Expr(TP.Module, 0, new List<Expr>());
                        module.List!.Add(new Expr(TP.Str, fullPath));
                        module.List!.Add(new Expr(TP.Str, script));
                        Env.ModuleMap[fullPath] = module;
                        return module;
                    }
                 
                }
                return Expr.Err("引入函数参数错误");
            }
            return Expr.Err("引入函数参数不足");
        }
    }


    class LoadDll : Native {
        public override string Name { get; set; } = "加载动态库";
        public override string Desc { get; set; } = "参数1-字符串，可选参数2-字符串，返回对象；加载参数1对应的动态库文件，参数2是动态库中用于对接青语言的类名，默认类名QingLib.LibObj，返回生成的对象";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count > 0 && args[0].Tp == TP.Str) {

                string libPath = "QingLib.LibObj";
                if(args.Count > 1 && args[1].Tp == TP.Str) {
                    libPath = args[1].Str();
                }

                try {
                    string path = args[0].Str();
                    if (!path.StartsWith("/") && !path.Contains(":")) {
                        path = Directory.GetCurrentDirectory() + '/' + path;
                    }

                    Assembly assembly = Assembly.LoadFile(path);
                    Type type = assembly.GetType(libPath)!;
                    object instance = assembly.CreateInstance(libPath)!;

                    Obj dllObj = (Obj)instance;

                    return new Expr(TP.Obj, dllObj);
                } catch(Exception e) {
                    return Expr.Err(e.Message);
                }
            }
            return Expr.Err("加载动态库函数参数错误");
        }
    }


    /*class RunCSharpScript : Native {
        public override string Name { get; set; } = "运行原生脚本";
        public override string Desc { get; set; } = "参数1-字符串，参数2-字符串，可选参数3-整数，返回空；运行C#脚本，参数3为模式，默认0，模式0-脚本文本，模式1-脚本文件，模式2-对象内运行脚本";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            int mode = 0;
            if(args.Count > 2) {
                mode = args[2].Int();
            }

            List<string> imports = new List<string> { "System"};
            if (args.Count > 3 && args[3].Tp == TP.Arr) {
                foreach(var item in args[3].List!) {
                    if(item.Tp == TP.Str) {
                        imports.Add(item.Str());
                    }
                }
            }

            if (args.Count >= 2 && args[0].Tp == TP.Str) {
                try {
                    
                    if(mode == 0) {
                        if (args[1].Tp == TP.Str) {
                            var script = CSharpScript.RunAsync(args[0].Str()).Result;
                            script.ContinueWithAsync<string>(args[1].Str(), ScriptOptions.Default.WithImports(imports.ToArray()));
                            return Expr.NoneExpr;
                        }
                        
                    }else if(mode == 1) {
                        string path = args[0].Str();
                        if(!path.StartsWith("/") && !path.Contains(":")) {
                            path = Directory.GetCurrentDirectory() + "/" + path;
                        }
                        if(!File.Exists(path)) {
                            return Expr.Err("要运行的原生脚本文件不存在");
                        }

                        var script = CSharpScript.RunAsync(File.ReadAllText(path)).Result;
                        script.ContinueWithAsync<string>(args[1].Str(), ScriptOptions.Default.WithImports(imports.ToArray()));
                        return Expr.NoneExpr;

                    } else if(mode == 2) {
                        CSharpScript.RunAsync(args[0].Str(), globals: args[1]);
                        return Expr.NoneExpr;
                    }
                    
                } catch (Exception e) {
                    return Expr.Err(e.Message);
                }
                

            }
            return Expr.Err("运行原生脚本函数参数错误");
        }
    }*/


}
